﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Star.Tools.Extensions
{
    /// <summary>
    /// Provides extensions for <see cref="Type"/> class.
    /// </summary>
    public static class TypeExtensions
    {
        /// <summary>
        ///数字类型集合
        /// </summary>
        private static readonly List<Type> NumericTypes = new List<Type>
        {
            typeof(decimal),
            typeof(byte),
            typeof(sbyte),
            typeof(short),
            typeof(ushort),
            typeof(int),
            typeof(uint),
            typeof(long),
            typeof(ulong),
            typeof(float),
            typeof(double)
        };

        /// <summary>
        /// 检查给定类型是否为数字类型
        /// </summary>
        /// <param name="type">要检查的类型</param>
        public static bool IsNumeric(this Type type)
        {
            return NumericTypes.Contains(type);
        }

        /// <summary>
        /// 检查给定类型是否可空的类型
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static bool IsNullableType(Type type)
        {
            bool result = false;
            if (type != null &&type.IsGenericType &&  type.GetGenericTypeDefinition() == typeof(Nullable<>))
            {
                result = true;
            }
            return result;
        }
        /// <summary>
        /// 获取可空类型的实际类型
        /// </summary>
        /// <param name="conversionType"></param>
        /// <returns></returns>
        public static Type GetNullableType(Type type)
        {
            if (type != null && type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
            {
                //如果是泛型方法，且泛型类型为Nullable<>则视为可空类型
                //并使用NullableConverter转换器进行转换
                var nullableConverter = new System.ComponentModel.NullableConverter(type);
                type = nullableConverter.UnderlyingType;
            }
            return type;
        }

        public static Type GetNullableTypeToString(Type type)
        {
            if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
            {
                //如果是泛型方法，且泛型类型为Nullable<>则视为可空类型
                //并使用NullableConverter转换器进行转换
                type = typeof(string);
            }
            return type;
        }

        /// <summary>
        /// 类型转换
        /// </summary>
        /// <param name="value">值</param>
        /// <param name="type">类型</param>
        /// <returns></returns>
        public static object ChangeType(object value, Type type)
        {
            if (value == null && type.IsGenericType) return Activator.CreateInstance(type);
            if (value == null) return null;
            if (type == value.GetType()) return value;
            if (type.IsEnum)
            {
                if (value is string)
                    return Enum.Parse(type, value as string);
                else
                    return Enum.ToObject(type, value);
            }
            if (!type.IsInterface && type.IsGenericType)
            {
                Type innerType = type.GetGenericArguments()[0];
                object innerValue = null;
                try
                {
                    innerValue = ChangeType(value, innerType);
                }
                catch
                {
                    return null;
                }
                try
                {
                    return Activator.CreateInstance(type, new object[] { innerValue });
                }
                catch
                {
                    return null;
                }
            }
            if (value is string && type == typeof(Guid)) return new Guid(value as string);
            if (value is string && type == typeof(Version)) return new Version(value as string);
            if (value is string && type == typeof(bool))
            {
                return ((value as string) == "1" || (value as string).ToLower() == "true") ? true : false;
            }
            if (type == typeof(long) || type == typeof(int) || type == typeof(short) ||
                type == typeof(float) || type == typeof(double) || type == typeof(decimal))
            {
                try
                {
                    return Convert.ChangeType(value, type);
                }
                catch
                {
                    return 0;
                }
            }
            if (!(value is IConvertible)) return value;
            return Convert.ChangeType(value, type);
        }

    }
}
